#ifndef _TEXTURE
#define _TEXTURE

#include <GL/glut.h>

class Texture {
public:
	float speed;
	unsigned char *flagData, *concreteData, *optionalData;
	GLuint texture[1];
	int flagWidth, flagHeight;
	int concreteWidth, concreteHeight;
	int optionalWidth, optionalHeight;

	Texture(){
		speed = 0.5;
		flagWidth = 128;
		flagHeight = 128;
		concreteWidth = 512;
		concreteHeight = 512;
		optionalWidth = 384;
		optionalHeight = 192;
	}

	void optionalTexture(){
		glBindTexture(GL_TEXTURE_2D, texture[0]);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, optionalWidth, optionalHeight, 0,
				GL_RGB, GL_UNSIGNED_BYTE, optionalData);
		// Select GL_MODULATE to mix texture with color for shading:
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		// Use bilinear filtering:
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		// Wrap texture over at the edges:
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	}

	void concreteTexture() {
		glBindTexture(GL_TEXTURE_2D, texture[0]);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, concreteWidth, concreteHeight, 0,
				GL_RGB, GL_UNSIGNED_BYTE, concreteData);
		// Select GL_MODULATE to mix texture with color for shading:
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		// Use bilinear filtering:
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		// Wrap texture over at the edges:
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	}

	void flagTexture() {
		glBindTexture(GL_TEXTURE_2D, texture[0]);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, flagWidth, flagHeight, 0,
				GL_RGB, GL_UNSIGNED_BYTE, flagData);
		// Select GL_MODULATE to mix texture with color for shading:
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		// Use bilinear filtering:
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		// Wrap texture over at the edges:
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	}

	void loadTexture() {
		concreteData =
				loadPPM(
						"/home/lonkz/workspace/project6/project6/src/Texture/Concrete.ppm",
						concreteWidth, concreteHeight);
		flagData =
				loadPPM(
						"/home/lonkz/workspace/project6/project6/src/Texture/Ucsd-logo.ppm",
						flagWidth, flagHeight);
		optionalData =
				loadPPM(
						"/home/lonkz/workspace/project6/project6/src/Texture/Optional.ppm",
						optionalWidth, optionalHeight);

		if (concreteData == NULL || flagData == NULL || optionalData == NULL)
			return;
	}

	unsigned char* loadPPM(const char* filename, int& width, int& height) {
		const int BUFSIZE = 128;
		FILE* fp;
		unsigned int read;
		unsigned char* rawData;
		char buf[3][BUFSIZE];
		char* retval_fgets;
		size_t retval_sscanf;

		if ((fp = fopen(filename, "rb")) == NULL) {
			std::cerr << "error reading ppm file, could not locate " << filename
					<< std::endl;
			width = 0;
			height = 0;
			return NULL;
		}

		// Read magic number:
		retval_fgets = fgets(buf[0], BUFSIZE, fp);

		// Read width and height:
		do {
			retval_fgets = fgets(buf[0], BUFSIZE, fp);
		} while (buf[0][0] == '#');
		retval_sscanf = sscanf(buf[0], "%s %s", buf[1], buf[2]);
		width = atoi(buf[1]);
		height = atoi(buf[2]);

		// Read maxval:
		do {
			retval_fgets = fgets(buf[0], BUFSIZE, fp);
		} while (buf[0][0] == '#');

		// Read image data:
		rawData = new unsigned char[width * height * 3];
		read = fread(rawData, width * height * 3, 1, fp);
		fclose(fp);
		if (read != 1) {
			std::cerr << "error parsing ppm file, incomplete data" << std::endl;
			delete[] rawData;
			width = 0;
			height = 0;
			return NULL;
		}

		return rawData;
	}
};

#endif
